#ifndef SPI_LCD_HPP
#define SPI_LCD_HPP

#include "spi.h"
#include "gpio.h"
#include "stm32f407xx.h"
#include "stdint.h"
#include "lcd_fonts.h"  // 字体文件

class SPILcd {
public:
    static SPILcd *getInstance(unsigned char index);

    bool init();                                // 初始化LCD
    void writeCommand(uint8_t cmd);             // 写命令
    void writeData(uint8_t data);               // 写数据（8位）
    void writeData16(uint16_t data);            // 写数据（16位）
    void writeBuff(uint16_t *data, uint16_t length);  // 发送16位数据数组

    void setDirection(uint8_t direction);               // 设置显示方向
    void setBackColor(uint32_t Color);  				//	设置背景颜色
    void setColor(uint32_t Color); 				        //	设置画笔颜色
    void setAddress(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); // 设置区域

    void clear();  // 清屏，填充背景色

    // 显示 ASCII 字符
    void setAsciiFont(pFONT *fonts);                          // 设置 ASCII 字体
    void displayChar(uint16_t x, uint16_t y, uint8_t c);      // 显示单个 ASCII 字符
    void displayString(uint16_t x, uint16_t y, char *p);      // 显示 ASCII 字符串

    // 显示中文字符和混合文本
    void setTextFont(pFONT *fonts);                           // 设置文本字体（中文 + ASCII）
    void displayChinese(uint16_t x, uint16_t y, char *pText); // 显示单个中文字符
    void displayText(uint16_t x, uint16_t y, char *pText);    // 显示字符串（中英文混排）

    // 显示数字（整数与浮点数）
    void setNumMode(uint8_t mode);                                                    // 设置数字显示格式（填充0或空格）
    void displayNumber(uint16_t x, uint16_t y, int32_t number, uint8_t len);          // 显示整数
    void displayDecimals(uint16_t x, uint16_t y, double decimals, uint8_t len, uint8_t decs); // 显示小数

    // 基础图形绘制
    void drawPoint565(uint16_t x, uint16_t y, uint16_t color565);
    void drawPoint(uint16_t x, uint16_t y, uint32_t color);
    void drawPoint(uint16_t x, uint16_t y);
    void drawLineV(uint16_t x, uint16_t y, uint16_t height);
    void drawLineH(uint16_t x, uint16_t y, uint16_t width);
    void drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
    void drawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
    void drawCircle(uint16_t x, uint16_t y, uint16_t r);
    void drawEllipse(int x, int y, int r1, int r2);

    // 区域填充
    void fillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
    void fillCircle(uint16_t x, uint16_t y, uint16_t r);
    void fillFlush(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t* color); // 填充区域（使用 DMA 方式）   

    // 单色图像绘制
    void drawImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *pImage);

    void enableBacklight();                     // 打开背光
    void disableBacklight();                    // 关闭背光

    void dmaWrite(uint16_t *data, uint32_t length); // DMA 方式传输数据
    void beginWrite();  // 开始通信（片选拉低）
    void endWrite();    // 结束通信（片选拉高）

private:
    explicit SPILcd(unsigned char index);
    static SPILcd *instances[2];
    bool initialized = false;
    unsigned char lcd_index;

    SPI_HandleTypeDef *hspi;
    GPIO_TypeDef *cs_port;
    uint16_t cs_pin;
    GPIO_TypeDef *dc_port;
    uint16_t dc_pin;
    GPIO_TypeDef *bl_port;
    uint16_t bl_pin;

    uint16_t drawBuffer[1024];  // 类成员变量

    pFONT *asciiFont = nullptr;   // 当前 ASCII 字体
    pFONT *textFont  = nullptr;   // 当前 中文字体（包含 ASCII + 中文）

    /* LCD相关参数 */
    uint32_t Color;  				//	LCD当前画笔颜色
    uint32_t BackColor;			//	背景色
    uint8_t  ShowNum_Mode;		// 数字显示模式
    uint8_t  Direction;			//	显示方向
    uint16_t Width;            // 屏幕像素长度
    uint16_t Height;           // 屏幕像素宽度	
    uint8_t  X_Offset;         // X坐标偏移，用于设置屏幕控制器的显存写入方式
    uint8_t  Y_Offset;         // Y坐标偏移，用于设置屏幕控制器的显存写入方式

    void dcCommand();
    void dcData();
};

/*----------------------------------------------- 参数宏 -------------------------------------------*/

#define LCD_Width     240		// LCD的像素长度
#define LCD_Height    240		// LCD的像素宽度

// 显示方向参数
// 使用示例：LCD_DisplayDirection(Direction_H) 设置屏幕横屏显示
#define	Direction_H				0					//LCD横屏显示
#define	Direction_H_Flip	    1					//LCD横屏显示,上下翻转
#define	Direction_V				2					//LCD竖屏显示 
#define	Direction_V_Flip	    3					//LCD竖屏显示,上下翻转 

// 设置变量显示时多余位补0还是补空格
// 只有 LCD_DisplayNumber() 显示整数 和 LCD_DisplayDecimals()显示小数 这两个函数用到
// 使用示例： LCD_ShowNumMode(Fill_Zero) 设置多余位填充0，例如 123 可以显示为 000123
#define  Fill_Zero  0		//填充0
#define  Fill_Space 1		//填充空格


/*---------------------------------------- 常用颜色 ------------------------------------------------------

 1. 这里为了方便用户使用，定义的是24位 RGB888颜色，然后再通过代码自动转换成 16位 RGB565 的颜色
 2. 24位的颜色中，从高位到低位分别对应 R、G、B  3个颜色通道
 3. 用户可以在电脑用调色板获取24位RGB颜色，再将颜色输入LCD_SetColor()或LCD_SetBackColor()就可以显示出相应的颜色 
 */                                                  						
#define 	LCD_WHITE       0xFFFFFF	 // 纯白色
#define 	LCD_BLACK       0x000000    // 纯黑色
                        
#define 	LCD_BLUE        0x0000FF	 //	纯蓝色
#define 	LCD_GREEN       0x00FF00    //	纯绿色
#define 	LCD_RED         0xFF0000    //	纯红色
#define 	LCD_CYAN        0x00FFFF    //	蓝绿色
#define 	LCD_MAGENTA     0xFF00FF    //	紫红色
#define 	LCD_YELLOW      0xFFFF00    //	黄色
#define 	LCD_GREY        0x2C2C2C    //	灰色
												
#define 	LIGHT_BLUE      0x8080FF    //	亮蓝色
#define 	LIGHT_GREEN     0x80FF80    //	亮绿色
#define 	LIGHT_RED       0xFF8080    //	亮红色
#define 	LIGHT_CYAN      0x80FFFF    //	亮蓝绿色
#define 	LIGHT_MAGENTA   0xFF80FF    //	亮紫红色
#define 	LIGHT_YELLOW    0xFFFF80    //	亮黄色
#define 	LIGHT_GREY      0xA3A3A3    //	亮灰色
												
#define 	DARK_BLUE       0x000080    //	暗蓝色
#define 	DARK_GREEN      0x008000    //	暗绿色
#define 	DARK_RED        0x800000    //	暗红色
#define 	DARK_CYAN       0x008080    //	暗蓝绿色
#define 	DARK_MAGENTA    0x800080    //	暗紫红色
#define 	DARK_YELLOW     0x808000    //	暗黄色
#define 	DARK_GREY       0x404040    //	暗灰色

#endif // SPI_LCD_HPP
